﻿using Microsoft.EntityFrameworkCore;
using NewRetail.Application.Components.Goods.Entity;
using NewRetail.Application.Components.Platform.Entity;
using NewRetail.Application.Components.Warehouse.Entity;
using NewRetail.Application.Core;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;

namespace NewRetail.Application.Components.Warehouse
{
    public class QueryInOutWarehouseSummaryGroupDto
    {
        public int? InOrOut { get; set; }
        public DateTime? startTime { get; set; }
        public DateTime? endTime { get; set; }
    }

    public class QueryInOutWarehouseSummaryGroupResult
    {
        public string warehouseID { get; set; }
        public string supplierID { get; set; }
        public decimal quantity { get; set; }
        public decimal price { get; set; }
        public Supplier Supplier { get; set; }
        public Warehouse.Entity.Warehouse Warehouse { get; set; }
        //add 20240306
        /// <summary>
        /// 进货金额
        /// </summary>
        public decimal inAmount { get; set; } = 0;
        /// <summary>
        /// 退货金额
        /// </summary>
        public decimal outAmount { get; set; } = 0;
        /// <summary>
        /// 进货数量
        /// </summary>
        public decimal inQuantity { get; set; }
        /// <summary>
        /// 退货数量
        /// </summary>
        public decimal outQuantity { get; set; }
    }

    public class QueryInOutWarehouseDetailGroupDto
    {
        public int? InOrOut { get; set; }
        public DateTime? startTime { get; set; }
        public DateTime? endTime { get; set; }
    }

    public class QueryInOutWarehouseDetailGroupResult
    {
        public string receiptNo { get; set; }
        public string warehouseID { get; set; }
        public string supplierID { get; set; }
        public string goodsID { get; set; }
        public decimal quantity { get; set; }
        public decimal price { get; set; }
        public Supplier Supplier { get; set; }
        public Warehouse.Entity.Warehouse Warehouse { get; set; }
        public GoodsInfo GoodsInfo { get; set; }
    }

    public class QueryMobileInOutWarehouseSummaryGroupResult
    {
        public string warehouseID { get; set; }
        public int InOrOut { get; set; }
        public decimal quantity { get; set; }
        public decimal price { get; set; }
    }

    public interface IInOutWarehouseService : IApplicationService
    {
        /// <summary>
        /// 查询汇总
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        Task<QueryInOutWarehouseSummaryGroupResult[]> QueryStatisticsSummary(QueryInOutWarehouseSummaryGroupDto dto);

        /// <summary>
        /// 查询明细
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        Task<QueryInOutWarehouseDetailGroupResult[]> QueryStatisticsDetail(QueryInOutWarehouseDetailGroupDto dto);

        Task<InOutWarehousing[]> AttachGoodsInfo(InOutWarehousing[] data);
        Task<InOutWarehousing[]> AttachWarehouse(InOutWarehousing[] data);
        Task<InOutWarehousing[]> AttachSupplier(InOutWarehousing[] data);
        /// <summary>
        /// 获取掌售通首页的采购入库/退货数据统计
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        Task<QueryMobileInOutWarehouseSummaryGroupResult[]> QueryMobileHomeOrderSummary(QueryInOutWarehouseSummaryGroupDto dto);
    }

    public class InOutWarehouseService : MyApplicationService, IInOutWarehouseService
    {
        private readonly IRepository<InOutWarehousing> inOutWarehousings;

        public InOutWarehouseService(IRepository<InOutWarehousing> inOutWarehousings)
        {
            this.inOutWarehousings = inOutWarehousings;
        }

        public async Task<InOutWarehousing[]> AttachGoodsInfo(InOutWarehousing[] data)
        {
            var db = await this.inOutWarehousings.GetDbContextAsync();

            await db.AttachData<GoodsInfo, InOutWarehousing>(data, x => x.goodsID, (m, arr) =>
            {
                m.GoodsInfo = arr.FirstOrDefault();
            });

            return data;
        }

        public async Task<InOutWarehousing[]> AttachWarehouse(InOutWarehousing[] data)
        {
            var db = await this.inOutWarehousings.GetDbContextAsync();

            await db.AttachData<Warehouse.Entity.Warehouse, InOutWarehousing>(data, x => x.warehouseID, (m, arr) =>
            {
                m.Warehouse = arr.FirstOrDefault();
            });

            return data;
        }

        public async Task<InOutWarehousing[]> AttachSupplier(InOutWarehousing[] data)
        {
            var db = await this.inOutWarehousings.GetDbContextAsync();

            await db.AttachData<Supplier, InOutWarehousing>(data, x => x.supplierID, (m, arr) =>
            {
                m.Supplier = arr.FirstOrDefault();
            });

            return data;
        }

        public async Task<QueryInOutWarehouseSummaryGroupResult[]> QueryStatisticsSummary(QueryInOutWarehouseSummaryGroupDto dto)
        {
            var db = await this.inOutWarehousings.GetDbContextAsync();
            //
            var query = db.Set<InOutWarehousing>().AsNoTracking();

            query = this.SingleStoreService.ApplyToQueryable(query);

            query = query.Where(x => x.isAuditing);
            if (dto.InOrOut != null)
            {
                query = query.Where(x => x.inOrOut == dto.InOrOut.Value);
            }
            query = query.WhereIf(dto.startTime != null, x => x.addTime >= dto.startTime.Value);
            query = query.WhereIf(dto.endTime != null, x => x.addTime < dto.endTime.Value);

            var data = await query
                .GroupBy(x => new { x.warehouseID, x.supplierID })
                .Select(x => new
                {
                    x.Key.warehouseID,
                    x.Key.supplierID,
                    quantity = x.Sum(x => x.quantity),
                    price = x.Sum(x => x.price),
                    inAmount = x.Sum(d => d.inOrOut == (int)InOrOutEnum.IN ? (d.price*d.quantity) : 0),
                    outAmount = x.Sum(d => d.inOrOut == (int)InOrOutEnum.OUT ? (d.price * d.quantity) : 0),
                    inQuantity = x.Sum(d => d.inOrOut == (int)InOrOutEnum.IN ? d.quantity : 0),
                    outQuantity = x.Sum(d => d.inOrOut == (int)InOrOutEnum.OUT ? d.quantity : 0)
                })
                .OrderByDescending(x => x.price)
                .MaxTake()
                .ToArrayAsync();

            var res = data.Select(x => new QueryInOutWarehouseSummaryGroupResult()
            {
                warehouseID = x.warehouseID,
                supplierID = x.supplierID,
                quantity = x.quantity,
                price = x.price,
                inAmount = x.inAmount,
                outAmount = x.outAmount,
                inQuantity = x.inQuantity,
                outQuantity = x.outQuantity
            }).ToArray();

            await db.AttachData<Warehouse.Entity.Warehouse, QueryInOutWarehouseSummaryGroupResult>(res,
                idGetter: x => x.warehouseID,
                action: (m, arr) => m.Warehouse = arr.FirstOrDefault());

            await db.AttachData<Supplier, QueryInOutWarehouseSummaryGroupResult>(res,
                idGetter: x => x.supplierID,
                action: (m, arr) => m.Supplier = arr.FirstOrDefault());

            return res;
        }

        public async Task<QueryInOutWarehouseDetailGroupResult[]> QueryStatisticsDetail(QueryInOutWarehouseDetailGroupDto dto)
        {
            var db = await this.inOutWarehousings.GetDbContextAsync();
            //
            var query = db.Set<InOutWarehousing>().AsNoTracking();

            query = this.SingleStoreService.ApplyToQueryable(query);

            query = query.Where(x => x.isAuditing);
            if (dto.InOrOut != null)
            {
                query = query.Where(x => x.inOrOut == dto.InOrOut.Value);
            }
            query = query.WhereIf(dto.startTime != null, x => x.addTime >= dto.startTime.Value);
            query = query.WhereIf(dto.endTime != null, x => x.addTime < dto.endTime.Value);

            var data = await query
                .GroupBy(x => new { x.receiptNo, x.warehouseID, x.supplierID, x.goodsID })
                .Select(x => new
                {
                    x.Key.warehouseID,
                    x.Key.supplierID,
                    x.Key.goodsID,
                    quantity = x.Sum(x => x.quantity),
                    price = x.Sum(x => x.price),
                    x.Key.receiptNo
                })
                .OrderByDescending(x => x.price)
                .MaxTake()
                .ToArrayAsync();

            var res = data.Select(x => new QueryInOutWarehouseDetailGroupResult()
            {
                receiptNo = x.receiptNo,
                warehouseID = x.warehouseID,
                supplierID = x.supplierID,
                goodsID = x.goodsID,
                quantity = x.quantity,
                price = x.price

            }).ToArray();

            await db.AttachData<Warehouse.Entity.Warehouse, QueryInOutWarehouseDetailGroupResult>(res,
                idGetter: x => x.warehouseID,
                action: (m, arr) => m.Warehouse = arr.FirstOrDefault());

            await db.AttachData<Supplier, QueryInOutWarehouseDetailGroupResult>(res,
                idGetter: x => x.supplierID,
                action: (m, arr) => m.Supplier = arr.FirstOrDefault());

            await db.AttachData<GoodsInfo, QueryInOutWarehouseDetailGroupResult>(res,
                idGetter: x => x.goodsID,
                action: (m, arr) => m.GoodsInfo = arr.FirstOrDefault());

            return res;
        }

        #region 获取掌售通首页的采购入库/退货数据统计
        /// <summary>
        /// 获取掌售通首页的采购入库/退货数据统计
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<QueryMobileInOutWarehouseSummaryGroupResult[]> QueryMobileHomeOrderSummary(QueryInOutWarehouseSummaryGroupDto dto)
        {
            var db = await this.inOutWarehousings.GetDbContextAsync();
            //
            var query = db.Set<InOutWarehousing>().AsNoTracking();

            query = this.SingleStoreService.ApplyToQueryable(query);

            query = query.Where(x => x.isAuditing);
            if (dto.InOrOut != null)
            {
                query = query.Where(x => x.inOrOut == dto.InOrOut.Value);
            }
            query = query.WhereIf(dto.startTime != null, x => x.addTime >= dto.startTime.Value);
            query = query.WhereIf(dto.endTime != null, x => x.addTime < dto.endTime.Value);

            var data = await query
                .GroupBy(x => new { x.warehouseID, x.inOrOut })
                .Select(x => new
                {
                    x.Key.warehouseID,
                    x.Key.inOrOut,
                    quantity = x.Sum(x => x.quantity),
                    price = x.Sum(x => x.price)
                })
                .OrderByDescending(x => x.price)
                .MaxTake()
                .ToArrayAsync();

            var res = data.Select(x => new QueryMobileInOutWarehouseSummaryGroupResult()
            {
                warehouseID = x.warehouseID,
                InOrOut = x.inOrOut,
                quantity = x.quantity,
                price = x.price
            }).ToArray();
            //由于统计总的，所以不需要仓库和供应商详情
            //await db.AttachData<Warehouse.Entity.Warehouse, QueryInOutWarehouseSummaryGroupResult>(res,
            //    idGetter: x => x.warehouseID,
            //    action: (m, arr) => m.Warehouse = arr.FirstOrDefault());

            //await db.AttachData<Supplier, QueryInOutWarehouseSummaryGroupResult>(res,
            //    idGetter: x => x.supplierID,
            //    action: (m, arr) => m.Supplier = arr.FirstOrDefault());

            return res;
        }
        #endregion
    }
}
